home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Online / NNTPd / server / misc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-15  |  22.1 KB  |  1,064 lines

  1. #ifndef lint
  2. static char    sccsid[] = "@(#)$Id: misc.c,v 1.47 1995/01/01 03:39:24 sob Exp sob $";
  3. #endif
  4.  
  5. #include "common.h"
  6.  
  7. /* forward declarations */
  8. void close_crnt();
  9. void get_id();
  10.  
  11. /*
  12.  * open_valid_art -- determine if a given article name is valid;
  13.  *        if it is, return a file pointer to the open article,
  14.  *        along with a unique id of the article.
  15.  *
  16.  *    Parameters:    "artname" is a string containing the
  17.  *            name of the article.
  18.  *            "id" is space for us to put the article
  19.  *            id in.
  20.  *
  21.  *    Returns:    File pointer to the open article if the
  22.  *            article is valid; NULL otherwise
  23.  *
  24.  *    Side effects:    None.
  25.  */
  26.  
  27. FILE *
  28. open_valid_art(artname, id)
  29.     char        *artname;
  30.     char        *id;
  31. {
  32.     static int    crnt_art_num;
  33.     static char    crnt_art_id[MAXBUFLEN];
  34.     int        fd;
  35.     struct stat    statbuf;
  36.  
  37.     if (art_fp != NULL) {
  38.         if (crnt_art_num == atoi(artname)) {
  39.             if (fseek(art_fp, (long) 0, 0) < 0)
  40.                 close_crnt();
  41.             else {
  42.                 (void) strcpy(id, crnt_art_id);
  43.                 return (art_fp);
  44.             }
  45.         } else 
  46.             close_crnt();
  47.     }
  48.  
  49.     art_fp = fopen(artname, "r");
  50.  
  51.     if (art_fp == NULL)
  52.         return (NULL);
  53.  
  54.     fd = fileno(art_fp);
  55.  
  56.     if (fstat(fd, &statbuf) < 0) {
  57.         close_crnt();
  58.         return (NULL);
  59.     }
  60.  
  61.     if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
  62.         close_crnt();
  63.         return (NULL);
  64.     }
  65.  
  66.     get_id(art_fp, id);
  67.     (void) strcpy(crnt_art_id, id);
  68.     crnt_art_num = atoi(artname);
  69.     return (art_fp);
  70. }
  71.  
  72.  
  73. /*
  74.  * gethistent -- return the path name of an article if it's
  75.  * in the history file.
  76.  *
  77.  *    Parameters:    "msg_id" is the message ID of the
  78.  *            article, enclosed in <>'s.
  79.  *            "lookup", only check if article exists
  80.  *
  81.  *    Returns:    A char pointer to a static data area
  82.  *            containing the full pathname of the
  83.  *            article, or NULL if the message-id is not
  84.  *            in the history file.
  85.  *
  86.  *    Side effects:    opens dbm database
  87.  *            (only once, keeps it open after that).
  88.  *            If running Bnews, converts "msg_id" to lower case.
  89.  *            If running Cnews, converts "msg_id" per rfc822.
  90.  *            If in a group, sets group_artnum to appropriate value.
  91.  *            
  92.  */
  93.  
  94. #ifndef NDBM
  95. # ifndef DBM
  96. #  ifndef USGHIST
  97. #   define USGHIST
  98. #  endif
  99. # endif
  100. #endif
  101.  
  102. char *
  103. gethistent(msg_id, lookup)
  104.     char        *msg_id;
  105.     int        lookup;
  106. {
  107.     char        line[MAXBUFLEN];
  108.     char        *tmp;
  109.     register char    *cp;
  110.     char        *s;
  111.     long        ltmp;
  112.     static char    path[MAXPATHLEN];
  113. #ifdef USGHIST
  114.     char        *histfile();
  115.     register int    len;
  116. #else
  117. #ifdef DBM
  118.     static int    dbopen = 0;
  119.     datum        fetch();
  120. #else
  121.     static DBM    *db = NULL;    /* History file, dbm version */
  122. #endif /* !DBM */
  123.     datum         key, content;
  124. #endif /* !USGHIST */
  125.     static FILE    *hfp = NULL;    /* history file, text version */
  126.  
  127. #ifdef CNEWS
  128.     cp = rindex(msg_id,'@');    /* look for @ in message id */
  129.     if( cp != NULL)
  130.     {    
  131.         for(;*cp != '\0';++cp)
  132. #else
  133.     {
  134.         for (cp = msg_id; *cp != '\0'; ++cp)
  135. #endif
  136.         if (isupper(*cp))
  137.             *cp = tolower(*cp);
  138. /* Make ctags happy */
  139. #ifdef CNEWS
  140.     }
  141. #else
  142.     }
  143. #endif
  144. #ifdef USGHIST
  145.     hfp = fopen(histfile(msg_id), "r");
  146.     if (hfp == NULL) {
  147. #ifdef SYSLOG
  148.         syslog(LOG_ERR, "gethistent: histfile: %m");
  149. #endif
  150.         return (NULL);
  151.     }
  152.  
  153.     len = strlen(msg_id);
  154.     while (fgets(line, sizeof (line), hfp))
  155.         if (!strncasecmp(msg_id, line, len))
  156.             break;
  157.  
  158.     if (feof(hfp)) {
  159.         (void) fclose(hfp);
  160.         return (NULL);
  161.     }
  162. #else /* !USGHIST */
  163. #ifdef DBM
  164.     if (!dbopen) {
  165.         if (dbminit(historyfile) < 0) {
  166. #ifdef SYSLOG
  167.             syslog(LOG_ERR, "openartbyid: dbminit %s: %m",
  168.                 historyfile);
  169. #endif
  170.             return (NULL);
  171.         } else
  172.             dbopen = 1;
  173.     }
  174. #else /* !DBM (ndbm) */
  175.     if (db == NULL) {
  176.         db = dbm_open(historyfile, O_RDONLY, 0);
  177.         if (db == NULL) {
  178. #ifdef SYSLOG
  179.             syslog(LOG_ERR, "openartbyid: dbm_open %s: %m",
  180.                 historyfile);
  181. #endif
  182.             return (NULL);
  183.         }
  184.     }
  185. #endif /* !DBM */
  186.  
  187.     key.dptr = msg_id;
  188.     key.dsize = strlen(msg_id) + 1;
  189.  
  190. #ifdef DBM
  191.     content = fetch(key);
  192. #else /* !DBM (ndbm) */
  193.     content = dbm_fetch(db, key);
  194. #endif
  195.     if (content.dptr == NULL)
  196.         return (NULL);
  197.  
  198.     /*
  199.      * If we are just checking to see if it exists return a non-NULL
  200.      * result
  201.      */
  202.     if (lookup)
  203.         return ((char *)1);
  204.  
  205.     if (hfp == NULL) {
  206.         hfp = fopen(historyfile, "r");
  207.         if (hfp == NULL) {
  208. #ifdef SYSLOG
  209.             syslog(LOG_ERR, "message: fopen %s: %m",
  210.                 historyfile);
  211. #endif
  212.             return (NULL);
  213.         }
  214.     } else {
  215. /* Why do this if we are going to do an absolute fseek below? XXX */
  216.         rewind(hfp);
  217.     }
  218.  
  219.     bcopy(content.dptr, (char *)<mp, sizeof (long));
  220.     if (fseek(hfp, ltmp, 0) < 0) {
  221. #ifdef SYSLOG
  222.         syslog(LOG_ERR, "message: %s: fseek to %ld on %d: %m", 
  223.                historyfile, ltmp, hfp);
  224. #endif
  225.         return (NULL);
  226.     }
  227.  
  228.     (void) fgets(line, sizeof(line), hfp);
  229. #endif /* USGHIST */
  230.  
  231.     if ((cp = index(line, '\n')) != NULL)
  232.         *cp = '\0';
  233.     cp = index(line, '\t');
  234.     if (cp != NULL)
  235.         cp = index(cp+1, '\t');
  236. #ifdef SYSLOG
  237.     else
  238.         syslog(LOG_ERR,
  239.         "message: malformed line in history file at %ld bytes, id %s",
  240.             ltmp, msg_id);
  241. #endif
  242.     if (cp == NULL) return(NULL); /* this article has expired */
  243.     tmp = cp+1;
  244.     group_artnum = 0;
  245.     if (group_name) {
  246.         int glen = strlen(group_name);
  247.         for (;;) {
  248.             if (!strncmp(group_name,tmp,glen) && tmp[glen] == '/') {
  249.                 group_artnum = atol(tmp+glen+1);
  250.                 break;
  251.             }
  252.             cp = index(tmp, ' ');
  253.             if (cp == NULL) break;
  254.             tmp = cp+1;
  255.         }
  256.     }
  257.  
  258.     if ((cp = index(tmp, ' ')) != NULL)
  259.         *cp = '\0';
  260.     
  261.     while ((cp = index(tmp, '.')) != NULL)
  262.         *cp = '/';
  263.  
  264.     (void) strcpy(path, spooldir);
  265.     (void) strcat(path, "/");
  266.     (void) strcat(path, tmp);
  267. #ifdef USGHIST
  268.     (void) fclose(hfp);
  269. #endif
  270.     return (path);
  271. }
  272.  
  273. /*
  274.  * openartbyid -- open an article by message-id.
  275.  *
  276.  *    Arguments:    "msg_id" is the message-id of the article
  277.  *            to open.
  278.  *
  279.  *    Returns:    File pointer to opened article, or NULL if
  280.  *            the article was not in the history file or
  281.  *            could not be opened.
  282.  *
  283.  *    Side effects:    Opens article.
  284.  */
  285.  
  286. FILE *
  287. openartbyid(msg_id)
  288.     char    *msg_id;
  289. {
  290.     char    *path;
  291.  
  292.     path = gethistent(msg_id, 0);
  293.     if (path != NULL)
  294.         return (fopen(path, "r"));
  295.     else
  296.         return (NULL);
  297. }
  298.  
  299.  
  300. /*
  301.  * check_ngperm -- check to see if they're allowed to see this
  302.  * article by matching Newsgroups: and Distribution: line.
  303.  *
  304.  *    Parameters:    "fp" is the file pointer of this article.
  305.  *
  306.  *    Returns:    0 if they're not allowed to see it.
  307.  *            1 if they are.
  308.  *
  309.  *    Side effects:    None.
  310.  */
  311.  
  312. int
  313. check_ngperm(fp)
  314.     register FILE    *fp;
  315. {
  316.     char        buf[MAXBUFLEN];
  317.     register char    *cp;
  318.     static char    **ngarray;
  319.     int        ngcount = 0;
  320.  
  321.     if (ngpermcount == 0) {
  322.         if (ALLBUT == 0)
  323.             return 0;
  324.         return (1);
  325.     }
  326.  
  327.     while (fgets(buf, sizeof (buf), fp) != NULL) {
  328.         if (buf[0] == '\n')        /* End of header */
  329.             break;
  330.         if (buf[0] != 'N' && buf[0] != 'n')
  331.             continue;
  332.         cp = index(buf, '\n');
  333.         if (cp)
  334.             *cp = '\0';
  335.         cp = index(buf, ':');
  336.         if (cp == NULL)
  337.             continue;
  338.         *cp = '\0';
  339.         if (!strcasecmp(buf, "newsgroups")) {
  340.             ngcount = get_nglist(&ngarray, cp+2);
  341.             break;
  342.         }
  343.     }
  344.  
  345. #ifndef USG
  346.     (void) rewind(fp);
  347. #else
  348.     rewind(fp);
  349. #endif
  350.     if (ngcount == 0)    /* Either no newgroups or null entry */
  351.         return (1);
  352.  
  353.     return (ngmatch(s1strneql, ALLBUT,
  354.         ngpermlist, ngpermcount, ngarray, ngcount));
  355. }
  356.  
  357.  
  358. /*
  359.  * spew -- spew out the contents of a file to stdout, doing
  360.  * the necessary cr-lf additions at the end.  Finish with
  361.  * a "." on a line by itself, and an fflush(stdout).
  362.  *
  363.  *    Parameters:    "how" tells what part of the file we
  364.  *            want spewed:
  365.  *                ARTICLE   The entire thing.
  366.  *                HEAD      Just the first part.
  367.  *                BODY      Just the second part.
  368.  *            "fp" is the open file to spew from.
  369.  *
  370.  *    Returns:    Nothing.
  371.  *
  372.  *    Side effects:    Changes current position in file.
  373.  */
  374.  
  375. void
  376. spew(fp, how)
  377.     FILE        *fp;
  378.     int        how;
  379. {
  380.     char        line[NNTP_STRLEN];
  381.     register char    *cp;
  382.  
  383. #ifdef LOG
  384.     ++arts_acsd;
  385. #endif
  386.  
  387.     if (how == STAT) {
  388.         (void) fflush(stdout);
  389.         return;
  390.     }
  391.  
  392.     cp = line;
  393.     while (fgets(line, sizeof(line)-6, fp) != NULL
  394.         && (cp == NULL || *line != '\n')) {
  395.         if (how == BODY)    /* We need to skip this anyway */
  396.             continue;
  397.         if (cp != NULL && *line == '.')
  398.             putchar('.');
  399.         cp = index(line, '\n');
  400.         if (cp != NULL)
  401.             *cp = '\0';
  402.         fputs(line, stdout);
  403.         if (cp != NULL) {
  404.             putchar('\r');
  405.             putchar('\n');
  406.         }
  407.     }
  408.  
  409.     if (how == HEAD) {
  410.         putline(".");
  411.         (void) fflush(stdout);
  412.         return;
  413.     }
  414.     if (how == ARTICLE) {
  415.         putchar('\r');
  416.         putchar('\n');
  417.     }
  418.  
  419.     while (fgets(line, sizeof(line)-6, fp) != NULL) {
  420.         if (cp != NULL && *line == '.')
  421.             putchar('.');
  422.         cp = index(line, '\n');
  423.         if (cp != NULL)
  424.             *cp = '\0';
  425.         fputs(line, stdout);
  426.         if (cp != NULL) {
  427.             putchar('\r');
  428.             putchar('\n');
  429.         }
  430.     }
  431.     if (cp == NULL) {
  432.         putchar('\r');
  433.         putchar('\n');
  434.     }
  435.     putline(".");
  436.     (void) fflush(stdout);
  437. }
  438.  
  439.  
  440. /*
  441.  * get_id -- get the message id of the current article.
  442.  *
  443.  *    Parameters:    "art_fp" is a pointer to the open file.
  444.  *            "id" is space for the message ID.
  445.  *
  446.  *    Returns:    Nothing.
  447.  *
  448.  *    Side effects:    Seeks and rewinds on "art_fp".
  449.  *            Changes space pointed to by "id".
  450.  */
  451.  
  452. void
  453. get_id(art_fp, id)
  454.     register FILE    *art_fp;
  455.     char        *id;
  456. {
  457.     char        line[MAXBUFLEN];
  458.     register char    *cp;
  459.  
  460.     while (fgets(line, sizeof(line), art_fp) != NULL) {
  461.         if (*line == '\n')
  462.             break;
  463.         if (*line == 'M' || *line == 'm') {    /* "Message-ID" */
  464.             if ((cp = index(line, ' ')) != NULL) {
  465.                 *cp = '\0';
  466.                 if (!strcasecmp(line, "Message-ID:")) {
  467.                     (void) strcpy(id, cp + 1);
  468.                     if ((cp = index(id, '\n')) != NULL)
  469.                         *cp = '\0';
  470. #ifndef USG
  471.                     (void) rewind(art_fp);
  472. #else
  473.                     rewind(art_fp);
  474. #endif
  475.                     return;
  476.                 }
  477.             }
  478.         }
  479.     }
  480. #ifndef USG
  481.     (void) rewind(art_fp);
  482. #else
  483.     rewind(art_fp);
  484. #endif
  485.     (void) strcpy(id, "<0>");
  486. }
  487.         
  488.  
  489. /*
  490.  * close_crnt -- close the current article file pointer, if it's
  491.  *    open.
  492.  *
  493.  *    Parameters:    None.
  494.  *
  495.  *    Returns:    Nothing.
  496.  *
  497.  *    Side effects:    Closes "art_fp" if it's open; sets "art_fp" to NULL.
  498.  */
  499.  
  500. void
  501. close_crnt()
  502. {
  503.     if (art_fp != NULL)
  504.         (void) fclose(art_fp);
  505.     art_fp = NULL;
  506. }
  507.  
  508.  
  509. /*
  510.  * findart -- find an article number in the article array.
  511.  *
  512.  *    Parameters:    "artname" is a string containing
  513.  *            the name of the article.
  514.  *
  515.  *    Returns:    An index into "art_array",
  516.  *            or -1 if "artname" isn't in "art_array".
  517.  *            
  518.  *    Side effects:    None.
  519.  *
  520.  *    Improvement:    Replace this linear search with a binary one.
  521.  */
  522.  
  523. int
  524. findart(artname)
  525.     char        *artname;
  526. {
  527.     register int    i, artnum;
  528.  
  529.     artnum = atoi(artname);
  530.  
  531.     for (i = 0; i < num_arts; ++i)
  532.         if (art_array[i] == artnum)
  533.             return(i);
  534.  
  535.     return (-1);
  536. }
  537.  
  538.  
  539. /*
  540.  * get_distlist -- return a nicely set up array of distribution groups
  541.  * along with a count, when given an NNTP-spec distribution list
  542.  * in the form <dist1,dist2,...,distn>.
  543.  *
  544.  *    Parameters:        "array" is storage for our array,
  545.  *                set to point at some static data.
  546.  *                "list" is the NNTP distribution list.
  547.  *
  548.  *    Returns:        Number of distributions found.
  549.  *                -1 on error.
  550.  *
  551.  *    Side effects:        Changes static data area.
  552.  */
  553.  
  554. int
  555. get_distlist(array, list)
  556.     char        ***array;
  557.     char        *list;
  558. {
  559.     char        *cp;
  560.     int        distcount;
  561.     static char    **dist_list = (char **) NULL;
  562.  
  563.     if (list[0] != '<')
  564.         return (-1);
  565.  
  566.     cp = index(list + 1, '>');
  567.     if (cp != NULL)
  568.         *cp = '\0';
  569.     else
  570.         return (-1);
  571.  
  572.     for (cp = list + 1; *cp != '\0'; ++cp)
  573.         if (*cp == ',')
  574.             *cp = ' ';
  575.     distcount = parsit(list + 1, &dist_list);
  576.     *array = dist_list;
  577.     return (distcount);
  578. }
  579.  
  580.  
  581. /*
  582.  * lower -- convert a character to lower case, if it's upper case.
  583.  *
  584.  *    Parameters:    "c" is the character to be
  585.  *            converted.
  586.  *
  587.  *    Returns:    "c" if the character is not
  588.  *            upper case, otherwise the lower
  589.  *            case equivalent of "c".
  590.  *
  591.  *    Side effects:    None.
  592.  */
  593.  
  594. char
  595. lower(c)
  596.     register char    c;
  597. {
  598.     if (isascii(c) && isupper(c))
  599.         c = c - 'A' + 'a';
  600.     return (c);
  601. }
  602.  
  603.  
  604. /* the following is from news 2.11 */
  605.  
  606. #ifdef USGHIST
  607. /*
  608. ** Generate the appropriate history subfile name
  609. */
  610. char *
  611. histfile(hline)
  612. char *hline;
  613. {
  614.     char chr;    /* least significant digit of article number */
  615.     static char subfile[BUFSIZ];
  616.  
  617.     chr = findhfdigit(hline);
  618.     sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr);
  619.     return subfile;
  620. }
  621.  
  622. findhfdigit(fn)
  623. char *fn;
  624. {
  625.     register char *p;
  626.     register int chr;
  627.  
  628.     p = index(fn, '@');
  629.     if (p != NULL && p > fn)
  630.         chr = *(p - 1);
  631.     else
  632.         chr = '0';
  633.     if (!isdigit(chr))
  634.         chr = '0';
  635.     return chr;
  636. }
  637. #endif /* USGHIST */
  638.  
  639. #if defined(USG) && !defined(SVR4)
  640. int
  641. dup2(x,y)
  642. int x,y;
  643.     close(y); 
  644.     return(fcntl(x, F_DUPFD,y ));
  645. }
  646. #endif
  647.  
  648. /*
  649.  * The following is a mish-mosh of code submitted to the net
  650.  * by Stan Barber <sob@bcm.tmc.edu>, Tad Guy <tadguy@cs.odu.edu>,
  651.  * Chris Jepeway <jepeway@utkcs2.cs.utk.edu>, and Tom Lane <tgl@cs.cmu.edu>.
  652.  */
  653.  
  654. /*
  655.  * returns 1 if there are lots of free blocks for the nntp server to use;
  656.  * a zero value is the small number of blocks remaining (more or less).
  657.  */
  658. #define DFREE_OK    0
  659. #define DFREE_INODES    1
  660. #define DFREE_BLOCKS    2
  661. #define DFREE_ERR    3
  662.  
  663. int
  664. space(min_free)
  665. int min_free;
  666. {
  667.     int result, dfree();
  668.  
  669.     result = dfree(SPOOLDIR,min_free);
  670.     if (result == DFREE_OK) return(1);
  671. #ifdef SYSLOG
  672.     switch (result) {
  673.     case DFREE_ERR:
  674.         syslog(LOG_ERR,"dfree failed due to syscall error");
  675.         break;
  676. #ifdef LOG
  677.     case DFREE_INODES:
  678.         syslog(LOG_INFO,"no inodes on %s",SPOOLDIR);
  679.         break;
  680.     case DFREE_BLOCKS:
  681.         syslog(LOG_INFO,"no space on %s",SPOOLDIR);
  682.         break;
  683. #endif
  684.         }    
  685. #endif
  686.     return(0);
  687. }
  688.  
  689. /*
  690.  * Now we define the dfree() routine, which returns the free space
  691.  * on the file system containing the specified directory.
  692.  * Space is measured in kilobytes.
  693.  * A negative value is returned on error.
  694.  */
  695. #ifndef READ_SUPER
  696. #ifndef SVR4
  697. #if defined(sun) || defined(hpux) || defined(pyr) || defined(hp300) || defined(NeXT)
  698. #include <sys/vfs.h>
  699. #define statfilesys    statfs        /* routine to call when trying to  */
  700.                     /* stat a file system to get the # */
  701.                     /* of free blocks available       */
  702. typedef struct statfs statfs_type;    /* the data type into which statfs() */
  703.                     /* wants to return useful information*/
  704. #define bombed(call)    ((call) == -1)    /* boolean expression returning 1 if */
  705.                     /* a call to statfs() fails         */
  706. #define blkfree(fs)    ((fs).f_bfree)    /* given a statfs_type, return total */
  707.                     /* # of free blocks             */
  708. #define blkavail(fs)    ((fs).f_bavail)    /* given a statfs_type called fs,  */
  709.                     /* return # of blocks available to */
  710.                     /* a non-privileged user       */
  711. #define filfree(fs)    ((fs).f_ffree)    /* given a statfs_type called fs,  */
  712.                      /* return number of free inodes       */
  713. #else
  714. #if defined(BSD_44)
  715. #include <sys/types.h>
  716. #include <sys/mount.h>
  717. #define statfilesys    statfs
  718.                     /* stat a file system to get the # */
  719.                     /* of free blocks available       */
  720. typedef struct statfs statfs_type;    /* the data type into which statfs() */
  721.                     /* wants to return useful information*/
  722. #define bombed(call)    ((call) == -1)    /* boolean expression returning 1 if */
  723.                     /* a call to statfs() fails         */
  724. #define blkfree(fs)    ((fs).f_bfree)    /* given a statfs_type, return total */
  725.                     /* # of free blocks             */
  726. #define blkavail(fs)    ((fs).f_bfree)    /* given a statfs_type called fs,  */
  727.                     /* return # of blocks available to */
  728.                     /* a non-privileged user       */
  729. #define filfree(fs)    ((fs).f_ffree)    /* given a statfs_type called fs,  */
  730.                      /* return number of free inodes       */
  731. #endif /* BSD_44 */
  732. #endif
  733. #else  /* SVR4  */
  734. #include <sys/statvfs.h>
  735. #define statfilesys    statvfs        /* routine to call when trying to  */
  736.                     /* stat a file system to get the # */
  737.                     /* of free blocks available       */
  738. typedef struct statvfs statfs_type;    /* the data type into which statfs() */
  739.                     /* wants to return useful information*/
  740. #define bombed(call)    ((call) == -1)    /* boolean expression returning 1 if */
  741.                     /* a call to statfs() fails         */
  742. #define blkfree(fs)    ((fs).f_bfree)    /* given a statfs_type, return total */
  743.                     /* # of free blocks             */
  744. #define blkavail(fs)    ((fs).f_bavail)    /* given a statfs_type called fs,  */
  745.                     /* return # of blocks available to */
  746.                     /* a non-privileged user       */
  747. #define filfree(fs)    ((fs).f_ffree)    /* given a statfs_type called fs,  */
  748.                      /* return number of free inodes       */
  749. #endif  /* SVR4 */
  750.  
  751. #if defined(apollo)
  752. #include <sys/types.h>
  753. #include <sys/statfs.h>
  754. #define statfilesys(a,b)    statfs(a,b, sizeof(struct statfs), 0)        /* routine to call when trying to  */
  755.                     /* stat a file system to get the # */
  756.                     /* of free blocks available       */
  757. typedef struct statfs statfs_type;    /* the data type into which statfs() */
  758.                     /* wants to return useful information*/
  759. #define bombed(call)    ((call) == -1)    /* boolean expression returning 1 if */
  760.                     /* a call to statfs() fails         */
  761. #define blkfree(fs)    ((fs).f_bfree)    /* given a statfs_type, return total */
  762.                     /* # of free blocks             */
  763. #define blkavail(fs)    ((fs).f_bfree)    /* given a statfs_type called fs,  */
  764.                     /* return # of blocks available to */
  765.                     /* a non-privileged user       */
  766. #define filfree(fs)    ((fs).f_ffree)    /* given a statfs_type called fs,  */
  767.                      /* return number of free inodes       */
  768. #endif /* apollo */
  769.  
  770. #ifdef ultrix
  771. #include <sys/mount.h>
  772. typedef struct fs_data statfs_type;
  773. #define statfilesys    statfs
  774. #define bombed(call)    ((call) <= 0)
  775. #define blkfree(fs)    ((int)((fs).fd_req.bfree))
  776. #define blkavail(fs)    ((int)((fs).fd_req.bfreen))
  777. #define filfree(fs)    ((int)((fs).fd_req.gfree))
  778. #endif 
  779.  
  780. #if defined(USG) && !defined(hpux) && !defined(SVR4)
  781. #include <ustat.h>
  782. typedef struct ustat statfs_type;
  783. /*
  784.  * You've got to make calls to 2 functions to get
  785.  * free blocks on a USG system, so statfilesys can't just be a macro.
  786.  * written by Stan Barber <sob@watson.bcm.tmc.edu>
  787.  */
  788. int
  789. statfilesys(dir, fs)
  790. char *dir;
  791. statfs_type *fs;
  792. {
  793.     struct stat file;
  794.     if (stat(dir,&file)) return(-1);
  795.     if (ustat(file.st_dev, fs)) return(-2);
  796.     return(0);
  797. }
  798. #define bombed(call)    (call != 0)
  799. #define blkfree(fs)    ((fs).f_tfree)
  800. #define blkavail(fs)    ((fs).f_tfree)
  801.                 /* USG doesn't reserve blocks for root */
  802. #define filfree(fs)    ((fs).f_tinode)    
  803. #endif /* USG && !hpux  && !SVR4 */
  804.  
  805. #ifdef CMU_MACH
  806. /* This code supplied by Tom Lane <tgl@cs.cmu.edu> */
  807. #include <sys/ioctl.h>
  808. typedef struct fsparam statfs_type;
  809. int
  810. statfilesys(dir, fs)
  811. char *dir;
  812. statfs_type *fs;
  813. {
  814.     int fd;
  815.     fd = open(dir, O_RDONLY);
  816.     if (fd < 0) return(-1);
  817.     if (ioctl(fd, FIOCFSPARAM, fs) < 0) {
  818.     close(fd);
  819.     return(-2);
  820.     }
  821.     close(fd);
  822.     return(0);
  823. }
  824. #define bombed(call)    ((call) < 0)
  825. #define blkfree(fs)    ((fs).fsp_free-((fs).fsp_size*(fs).fsp_minfree+99)/100)
  826. #define blkavail(fs)    (-1)
  827. #endif /* CMU_MACH */
  828.  
  829. int
  830. dfree(spool,free_space)
  831. char *spool;
  832. int free_space;
  833. {
  834. #ifndef amiga
  835.     statfs_type fsys;
  836.     int err;
  837.  
  838.     if (bombed(err = statfilesys(SPOOLDIR, &fsys)))
  839.     return(DFREE_ERR);        /* can't get file system info */
  840. # if defined(filfree) && defined(MINFILES)
  841.      if (filfree(fsys) < MINFILES )
  842.      return( DFREE_INODES );
  843. # endif
  844.     if (blkavail(fsys) < 0L) {
  845.     /* the bavail field doesn't apply to this file system */
  846.     if(blkfree(fsys) < free_space)
  847.         return( DFREE_BLOCKS );
  848.      } else {
  849.     if (blkavail(fsys) < free_space )
  850.         return( DFREE_BLOCKS );
  851.      }
  852. #endif
  853.     return( DFREE_OK );
  854. }
  855.  
  856. #else /* READ_SUPER */
  857. /*
  858.  * This code is used if you've got to directly read the superblock
  859.  * to determine how much space you've got left.  It's copied from
  860.  * patches posted by Tad Guy <tadguy@cs.odu.edu>
  861.  */
  862.  
  863. #include <sys/fs.h>
  864. #include <fstab.h>
  865.  
  866. /*
  867.  * return the number of free kilobytes remaining on the filesystem where
  868.  * the named file resides.  returns -1 on error.
  869.  */
  870.  
  871. off_t lseek();
  872.  
  873. dfree(name, free_space)
  874. char *name;
  875. int free_space;
  876. {
  877.     struct stat namest, fsst;
  878.     struct fstab *fsp;
  879.     char lname[MAXPATHLEN];
  880.     int fd;
  881.     union {
  882.     struct fs u_fs;
  883.     char dummy[SBSIZE];
  884.     } sb;
  885. #define sblock sb.u_fs
  886.  
  887.     strcpy(lname,name);
  888.     do {
  889.     if (stat(lname,&namest))        /* if stat fails, die */
  890.     {
  891. #ifdef SYSLOG
  892.       syslog(LOG_ERR,"dfree stat(%s) failed: %m", lname);
  893. #endif
  894.       return  DFREE_ERR;            
  895.     }
  896.     if ((namest.st_mode & S_IFMT) == S_IFLNK) { /* if symlink */
  897.         if ((fd = readlink(lname,lname,sizeof(lname))) < 0) 
  898.         {
  899. #ifdef SYSLOG
  900.           syslog(LOG_ERR,"dfree readlink() failed: %m");
  901. #endif
  902.           return DFREE_ERR;
  903.         }
  904.         lname[fd] = '\0';
  905.     }
  906.     } while ((namest.st_mode & S_IFMT) == S_IFLNK);
  907.  
  908.     (void) setfsent();
  909.  
  910.     while (fsp = getfsent()) {
  911.     if (stat(fsp->fs_spec,&fsst))
  912.       continue;
  913.     if (fsst.st_rdev == namest.st_dev)
  914.       break;
  915.     }
  916.  
  917.     if (!fsp ||    (fd = open(fsp->fs_spec,O_RDONLY)) < 0) {
  918.     (void) endfsent();
  919. #ifdef SYSLOG
  920.     syslog(LOG_ERR,"dfree open(%s,O_RDONLY) failed: %m", fsp->fs_spec);
  921. #endif
  922.     return DFREE_ERR;
  923.     }
  924.     (void) endfsent();
  925.  
  926.     (void) lseek(fd,SBLOCK*DEV_BSIZE,L_SET);
  927.     if (read(fd,(char *)&sblock,SBSIZE) != SBSIZE ||
  928.     (sblock.fs_magic != FS_MAGIC))
  929.     {
  930. #ifdef SYSLOG
  931.       syslog(LOG_ERR,"dfree read() failed: %m");
  932. #endif
  933.       return DFREE_ERR;
  934.     }
  935.     (void) close(fd);
  936.  
  937. # if defined(filfree) && defined(MINFILES)
  938.     if (filfree(fsys) < MINFILES )
  939.     return( DFREE_INODES );
  940. # endif
  941.     if( ((((sblock.fs_dsize) * ( 100 - sblock.fs_minfree) / 100)
  942.       - ((sblock.fs_dsize) 
  943.          - (sblock.fs_cstotal.cs_nbfree 
  944.         * sblock.fs_frag + sblock.fs_cstotal.cs_nffree))) 
  945.      * sblock.fs_fsize / 1024) < free_space )
  946.     return( DFREE_BLOCKS );
  947.    return( DFREE_OK );
  948. }
  949.  
  950. #endif /* READ_SUPER */
  951.  
  952. #ifdef LOAD
  953. /*
  954. **  GETLA -- get the current load average
  955. **
  956. **    This code stolen from la.c. (And subsequently stolen from sendmail,
  957. **        conf.c for nntpd.)
  958. **
  959. **    Parameters:
  960. **        none.
  961. **
  962. **    Returns:
  963. **        The current load average as an integer.
  964. **
  965. **    Side Effects:
  966. **        none.
  967. */
  968.  
  969. #if defined(USG) && !defined(SVR4)
  970. int
  971. getla()
  972. {
  973.     return(0);
  974. }
  975. #else
  976. #include <nlist.h>
  977. #include <sys/ioctl.h>
  978.  
  979. struct    nlist Nl[] =
  980. {
  981. #ifdef SVR4
  982.     { "avenrun" },
  983. #else
  984. #ifdef bsdi
  985.     { "_averunnable" },
  986. #else
  987.     { "_avenrun" },
  988. #endif
  989. #endif
  990. #define    X_AVENRUN    0
  991.     { 0 },
  992. };
  993.  
  994. #ifdef SVR4
  995. #define KERNEL_FILE "/unix"
  996. #else
  997. #ifdef bsdi
  998. #define KERNEL_FILE "/bsd"
  999. #else
  1000. #define KERNEL_FILE "/vmunix"
  1001. #endif
  1002. #endif
  1003.  
  1004. #ifdef    SVR4
  1005. #ifndef FSHIFT
  1006. #define FSHIFT  8
  1007. #endif
  1008. #ifndef FSCALE
  1009. #define FSCALE  (1 << FSHIFT)
  1010. #endif
  1011. #endif
  1012.  
  1013. int
  1014. getla()
  1015. {
  1016.     static int kmem = -1;
  1017. # ifdef FSCALE
  1018.     long avenrun[3];
  1019. # else
  1020.     double avenrun[3];
  1021. # endif
  1022.     extern off_t lseek();
  1023.  
  1024.     if (kmem < 0) {
  1025.         kmem = open("/dev/kmem", 0, 0);
  1026.         if (kmem < 0) {
  1027. #ifdef SYSLOG
  1028.             syslog(LOG_ERR,"can't open /dev/kmem: %m");
  1029. #endif
  1030.             return (-1);
  1031.         }
  1032. #ifndef SVR4
  1033.         if (ioctl(kmem, (int) FIOCLEX, (char *) 0) < 0) {
  1034. #ifdef SYSLOG
  1035.             syslog(LOG_ERR,"ioctl FIOCLEX of /dev/kmem failed: %m");
  1036. #endif
  1037.         }
  1038. #endif /* !SVR4 */
  1039.         if (nlist(KERNEL_FILE, Nl) < 0 || Nl[X_AVENRUN].n_value == 0) {
  1040. #ifdef SYSLOG
  1041.             syslog(LOG_ERR,"nlist of %s failed: %m", KERNEL_FILE);
  1042. #endif
  1043.             return (-1);
  1044.         }
  1045.     }
  1046.     if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
  1047.         read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
  1048.     {
  1049.         /* thank you Ian */
  1050. #ifdef SYSLOG
  1051.         syslog(LOG_ERR,"lseek or read of /dev/kmem failed: %m");
  1052. #endif
  1053.         return (-1);
  1054.     }
  1055. # ifdef FSCALE
  1056.     return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
  1057. # else
  1058.     return ((int) (avenrun[0] + 0.5));
  1059. # endif
  1060. }
  1061. #endif
  1062. #endif /* LOAD */
  1063.